package ru.volgogradetzzz.math {
	//import ru.volgogradetzz.math.VMatrix4x4;
	/**
	 * ...
	 * @author nvc
	 */
	public class VVector3 {
		public static const ZERO:VVector3 = new VVector3();
		
		public var x:Number;
		public var y:Number;
		public var z:Number;
		public var w:Number;
		
		public function VVector3(x:Number = 0, y:Number = 0, z:Number = 0, w:Number = 1) {
			this.x = x;
			this.y = y;
			this.z = z;
			this.w = w;
		}
		
		public function setComponents(x:Number, y:Number, z:Number, w:Number):void {
			this.x = x;
			this.y = y;
			this.z = z;
			this.w = w;
		}
		
		public function multiplyByMatrix(m:VMatrix4x4):void {
			var tempX:Number = x;
			var tempY:Number = y;
			var tempZ:Number = z;
			var tempW:Number = w;
			x = tempX * m.m11 + tempY * m.m21 + tempZ * m.m31 + tempW * m.m41;
			y = tempX * m.m12 + tempY * m.m22 + tempZ * m.m32 + tempW * m.m42;
			z = tempX * m.m13 + tempY * m.m23 + tempZ * m.m33 + tempW * m.m43;
			w = tempX * m.m14 + tempY * m.m24 + tempZ * m.m34 + tempW * m.m44;
		}
		
		public function zero():void {
			x = y = z = 0;
		}
		
		public function negate():void {
			x = -x;
			y = -y;
			z = -z;
		}
		
		public function add(v:VVector3):void {
			x += v.x;
			y += v.y;
			z += v.z;
		}
		
		public function addReturn(v:VVector3):VVector3 {
			return new VVector3(x + v.x, y + v.y, z + v.z);
		}
		
		public function addCopyTo(v:VVector3, vCopyTo:VVector3):void {
			vCopyTo.x = x + v.x;
			vCopyTo.y = y + v.y;
			vCopyTo.z = z + v.z;
		}
		
		public function subtract(v:VVector3):void {
			x -= v.x;
			y -= v.y;
			z -= v.z;
		}
		
		public function subtractReturn(v:VVector3):VVector3 {
			return new VVector3(x - v.x, y - v.y, z - v.z);
		}
		
		public function subtractCopyTo(v:VVector3, vCopyTo:VVector3):void {
			vCopyTo.x = x - v.x;
			vCopyTo.y = y - v.y;
			vCopyTo.z = z - v.z;
		}
		
		public function scale(s:Number):void {
			x *= s;
			y *= s;
			z *= s;
			w *= s;
		}
		
		public function scaleReturn(s:Number):VVector3 {
			return new VVector3(x * s, y * s, z * s);
		}
		
		public function scaleCopyTo(s:Number, v:VVector3):void {
			v.x = x * s;
			v.y = y * s;
			v.z = z * s;
		}
		
		public function magnitude():Number {
			return Math.sqrt(x * x + y * y + z * z);
		}
		
		public function squareMagnitude():Number {
			return x * x + y * y + z * z;
		}
		
		public function dot(v:VVector3):Number {
			return x * v.x + y * v.y + z * v.z
		}
		
		public function cross(v:VVector3):VVector3 {
			return new VVector3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
		}
		
		public function crossCopyTo(v:VVector3, vCopyTo:VVector3):void {
			vCopyTo.x = y * v.z - z * v.y;
			vCopyTo.y = z * v.x - x * v.z;
			vCopyTo.z = x * v.y - y * v.x;
		}
		
		public function normalize():void {
			var mSquare:Number = x * x + y * y + z * z;
			if (mSquare > 0) {
				var temp:Number = 1 / Math.sqrt(mSquare);
				x *= temp;
				y *= temp;
				z *= temp;
			}else {
				x = 1;
				y = z = 0;
			}
		}
		
		public function normalizeReturn():VVector3 {
			var mSquare:Number = x * x + y * y + z * z;
			if (mSquare > 0)
			{
				var temp:Number = 1 / Math.sqrt(mSquare);
				return new VVector3(x * temp, y * temp, z * temp);
			}
			
			return new VVector3(1, 0, 0);
		}
		
		public function clone():VVector3 {
			return new VVector3(x, y, z, w);
		}
		
		public function copyTo(v:VVector3):void {
			v.x = x;
			v.y = y;
			v.z = z;
			v.w = w;
		}
		
		public function copyFrom(v:VVector3):void {
			x = v.x;
			y = v.y;
			z = v.z;
			w = v.w;
		}
		
		public function toString():String {
			return '( x = ' + x + ', y = ' + y + ', z = ' + z + ', w = ' + w + ' )';
		}
	}
}